#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <ctime>
#include <algorithm>
#include <cassert>

using namespace std;

//服务器结构
struct Server{
	string type;
	int cpuA, cpuB, memA, memB, serverCost, powerCost;
	float ratio;//cpu和内存的比值
	//空参构造器
	Server(){}
	//带参构造器
	Server(string type, int cpuCore, int memSize, int sCost, int pCost):type(type),serverCost(sCost),powerCost(pCost){
		this->cpuA = cpuCore / 2;
		this->cpuB = this->cpuA;
		this->memA = memSize / 2;
		this->memB = this->memA;
		this->ratio = (float)memSize/cpuCore;
	}
	//cpu和内存的比值从小到大进行排序。
	bool operator<(const Server &other) const{
		return (ratio < other.ratio) || (ratio==other.ratio && serverCost<other.serverCost);
	}
};

//虚拟机结构
struct VirtualMachine{
	string type;
	int cpuCore, memSize, isDual;
	float ratio;
	//空参构造器
	VirtualMachine(){}
	//带参构造器
	VirtualMachine(string type, int cpuCore, int memSize, int isDual):type(type),cpuCore(cpuCore),memSize(memSize),isDual(isDual){
		this->ratio = (float)memSize/cpuCore;
	}
	//cpu和内存的比值从小到大进行排序
	bool operator<(const VirtualMachine &other) const{
		return ratio < other.ratio;
	}
};

/******* 全局变量 ***********************/
unordered_map<string, Server> svInfos;
unordered_map<string, VirtualMachine> vmInfos;
#define Request vector<string>                  //表示请求。若Request长度为3，{"add","类型","id"}；若长度为2，{"del","id"}
vector<Request> reqInfos;                        //每日请求信息，每天需清零
unordered_map<string, string> vmToSv;            //每种类型的虚拟机该对应到哪台服务器上(key=虚拟机类型，value=服务器类型)
vector<Server> svResources;                      //已购服务器，每次购买都往尾部添加，其所在容器中的位置索引就是其编号
unordered_map<string, vector<int>> svMapBuy;     //每种类型的已购服务器(key=服务器类型，value=服务器编号数组)
unordered_map<string, vector<Request>> svMapReq; //每天对于各类服务器的请求（请求分波。key=服务器类型，value=请求数组）
#define DeployInfo vector<int>                 //虚拟机的部署信息。{服务器编号, 总占用cpu, 总占用mem, maybe 部署节点}。长度为3->双节点部署;当长度为4->单节点部署（0-A,1->B）
unordered_map<string, DeployInfo> vmOnServer;    //记录虚拟机运行在哪台服务器上(key=虚拟机id(不是类型), value={服务器编号,占用cpu,占用mem,部署节点})
vector<int> svRunVms;                            //记录已购的每台服务器上的各自运行的虚拟机数量
vector<string> res;                              //保存打印信息，方便一次性打印
vector<vector<string>> purchase_info;//每天的购买信息
vector<vector<string>> migrate_info;//每天的迁移信息
vector<vector<string>> deploy_info;//每天的部署信息
//提交时可能用不到的变量
# define INPUT_REDIRECTION "training-data/training-1.txt"  //输入重定向
# define OUTPUT_REDIRECTION "result.txt"                   //输出重定向
long long SERVERCOST=0, POWERCOST=0, TOTALCOST=0;          //各种成本
/*****************************************/
/********** 线程1变量 ********************/
vector<Server> svResources_1;
unordered_map<string, DeployInfo> vmOnServer_1;
/*****************************************/

/****************** 读数据构建各种类型的 服务器 和 虚拟机 ********************/
void readServer(string &serverType, string &cpuCore, string &memSize, string &serverCost, string &powerCost){
	string _serverType = "";
    for(int i =1; i<serverType.size()-1; i++) _serverType += serverType[i];
    int _cpuCore=0, _memSize=0, _serverCost=0, _powerCost=0;
    for(int i=0; i<cpuCore.size()-1; i++) _cpuCore = 10*_cpuCore + cpuCore[i] - '0';
    for(int i=0; i<memSize.size()-1; i++) _memSize = 10*_memSize + memSize[i] - '0';
    for(int i=0; i<serverCost.size()-1; i++) _serverCost = 10*_serverCost + serverCost[i] - '0';
    for(int i=0; i<powerCost.size()-1; i++) _powerCost = 10*_powerCost + powerCost[i] - '0';
	svInfos[_serverType] = Server{_serverType, _cpuCore, _memSize, _serverCost, _powerCost};
}
void readVm(string &vmType, string &cpuCore, string &memSize, string &isDual){
    string _vmType = "";
    for(int i=1; i<vmType.size()-1; i++) _vmType += vmType[i];
    int _cpuCore=0, _memSize=0, _isDual=0;
    for(int i=0; i<cpuCore.size()-1; i++) _cpuCore = _cpuCore*10 + cpuCore[i] - '0';
    for(int i=0; i<memSize.size()-1; i++) _memSize = _memSize*10 + memSize[i] - '0';
    if(isDual[0] == '1') _isDual = 1;
    vmInfos[_vmType] = VirtualMachine{_vmType, _cpuCore, _memSize, _isDual};
}
bool readServerAndVmInfos(){
	int svNum;//服务器数量
	string type, cpuCore, memSize, serverCost, powerCost, isDual;
	scanf("%d", &svNum);
	for (int i=0; i<svNum; i++){
		cin>>type>>cpuCore>>memSize>>serverCost>>powerCost;
		readServer(type, cpuCore, memSize, serverCost, powerCost);
	}
	
	int vmNum;//虚拟机数量
    scanf("%d",&vmNum);
	for (int i =0; i<vmNum; i++){
        cin>>type>>cpuCore>>memSize>>isDual;
        readVm(type, cpuCore, memSize, isDual);
    }
	return true;
}
/*****************************************************************************/

/************ 解决如何寻找每台虚拟机的最佳服务器 *************/
int binarySearch_left_bound(vector<Server> const &servers, float target_ratio){
	if(servers.size() == 0) return -1;
	int left=0, right=servers.size();
	while (left < right){
		int mid = (left + right) / 2;
		if (target_ratio == servers[mid].ratio){
			right = mid;//注意这里是个非常神奇的地方
		}else if (target_ratio > servers[mid].ratio){
			left = mid + 1;
		}else if (target_ratio < servers[mid].ratio){
			right = mid;
		}
	}
	if (left == servers.size()) left--;
	return left;
}
string getMostSuitableServer(VirtualMachine const &vm, vector<Server> const &servers){
	float ratio = vm.ratio;
	int index = binarySearch_left_bound(servers, ratio);
	Server sv = servers[index];//理想的比较匹配的服务器，但是可能放不下当前服务器
	int needCpuCore = vm.isDual==0 ? vm.cpuCore : vm.cpuCore/2;
	int needMemSize = vm.isDual==0 ? vm.memSize : vm.memSize/2;
	if(sv.cpuA>=needCpuCore && sv.memA>=needMemSize) return sv.type;//如果能放下就直接返回
	int l_idx=index-1, r_idx=index+1;
	while(l_idx > -1){//直接向左搜索，可能有Bug，不过目前没有遇到
		sv = servers[l_idx++];
		if (sv.cpuA>=needCpuCore && sv.memA>=needMemSize) return sv.type;
	}
	return "";//其实这个 "" 永远也得不到返回
}
void createVmMapToSV(){
	vector<Server> servers;
	for (auto const key_value:svInfos){
		Server sv = key_value.second;
		servers.push_back(sv);
	}
	sort(servers.begin(), servers.end());//排序
	for (auto const key_value:vmInfos){
		string vmType = key_value.first;
		VirtualMachine vm = key_value.second;
		vmToSv[vmType] = getMostSuitableServer(vm, servers);
	}
}
/*************************************************************/

/************** 读数据构建每日请求 ****************/
void readRequest(string &op, string & reqVmType, string &reqVmId){
	string _op, _reqVmType, _reqVmId;
    _op = op.substr(1, op.size()-2);
    _reqVmType = reqVmType.substr(0, reqVmType.size()-1);
    _reqVmId = reqVmId.substr(0, reqVmId.size() -1);
    reqInfos.push_back(Request{_op, _reqVmType, _reqVmId});
}
void readRequest(string &op, string &reqVmId){
	string _op, _reqVmId;
    _op = op.substr(1, op.size()-2);
    _reqVmId = reqVmId.substr(0, reqVmId.size()-1);
    reqInfos.push_back(Request{_op, _reqVmId});
}
/**************************************************/

//计算每日的耗电成本
void computePowerCost(){
	for(int i=0; i<svRunVms.size(); i++){
        if(svRunVms[i] != 0){
            POWERCOST += svResources[i].powerCost;
        }
    }
}

//将请求分流到每种类型的服务器上
void distributeRequests(){
	svMapReq.clear();//每天清空，重新算
	for(auto const &req:reqInfos){
		if(req.size()==3){//如果是添加请求
			string typeOfServer = vmToSv[req[1]];//获取到所放服务器的型号
			svMapReq[typeOfServer].push_back(req);
		}else {
			int svId = vmOnServer[req[1]][0];//获取到所放服务器的编号
			string typeOfServer=svResources[svId].type;//获取到所放服务器的型号
			svMapReq[typeOfServer].push_back(req);
		}
	}
}

//这个应该可以丢到多线程里面去处理
int handleBranchRequests(string const &svType, vector<Request> const &reqs){
	svResources_1 = svResources;//复制全局变量单独处理
	
	vmOnServer_1.clear();
	int buy_number = 0;//记录处理本波请求可能购买的服务器数量
	vector<int> svBuys=svMapBuy[svType];//这种类型的已购服务器。
	string vmType, vmId;//虚拟机类型、id
	int needCpu, needMem;
	for (Request const &req : reqs){
		if (req.size() == 3){//这是一条添加虚拟机的请求
			vmType=req[1], vmId=req[2];
			VirtualMachine const &vm = vmInfos[vmType];
			needCpu = vm.isDual==0 ? vm.cpuCore : vm.cpuCore / 2;
			needMem = vm.isDual==0 ? vm.memSize : vm.memSize / 2;
			int idx = 0;//标记当前访问的该类型的已购服务器
			while(idx < svBuys.size()){
				int svId = svBuys[idx];//获取服务器id
				Server &sv = svResources_1[svId];//用&是因为可能会修改服务器可用资源量
				if(vm.isDual){//需双节点部署
					if(sv.cpuA>=needCpu && sv.cpuB>=needCpu && sv.memA>=needMem && sv.memB>=needMem){
						sv.cpuA -= needCpu;
						sv.cpuB -= needCpu;
						sv.memA -= needMem;
						sv.memB -= needMem;
						vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem};//记录该虚拟机的部署信息，长度为3
						break;
					}
				}else{//需单节点部署
					//可以先判断一下A节点还是B节点剩得多
					if(sv.memA >= sv.memB){//A节点剩得多
						if(sv.cpuA>=needCpu && sv.memA>=needMem){//并且A节点能放下
							sv.cpuA -= needCpu;
							sv.memA -= needMem;
							vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem, 0};//记录该虚拟机的部署信息，长度为4。0表示部署到A节点
							break;
						}
						if(sv.cpuB>=needCpu && sv.memB>=needMem){//虽然A节点剩得多，但是A节点放不下，那么看B节点能不能放下
							sv.cpuB -= needCpu;
							sv.memB -= needMem;
							vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem, 1};//记录该虚拟机的部署信息，长度为4。1表示部署到B节点
							break;
						}
					}else{//B节点剩得多
						if(sv.cpuB>=needCpu && sv.memB>=needMem){//并且B节点能放下
							sv.cpuB -= needCpu;
							sv.memB -= needMem;
							vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem, 1};//记录该虚拟机的部署信息，长度为4。1表示部署到B节点
							break;
						}
						if(sv.cpuA>=needCpu && sv.memA>=needMem){//虽然B节点剩得多，但是B节点放不下，那么看A节点能不能放下
							sv.cpuA -= needCpu;
							sv.memA -= needMem;
							vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem, 0};//记录该虚拟机的部署信息，长度为4。0表示部署到A节点
							break;
						}
					}
				}
				idx++;
			}
			//说明该类已购服务器放不下了，买买买
			if(idx == svBuys.size()){
				int svId = svResources_1.size();//新买的服务器，它的id应该是这个
				Server sv = svInfos[svType];//购买一台该类型的服务器.注意这里没有用 & 
				if(vm.isDual){//双节点部署
					sv.cpuA -= needCpu;
					sv.cpuB -= needCpu;
					sv.memA -= needMem;
					sv.memB -= needMem;
					vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem};//记录该虚拟机的部署信息，长度为3
				}else{//单节点部署
					//新买服务器时，第一个虚拟机默认放在B节点上
					sv.cpuB -= needCpu;
					sv.memB -= needMem;
					vmOnServer_1[vmId] = DeployInfo{svId, needCpu, needMem, 1};//记录该虚拟机的部署信息，长度为4。1表示部署到B节点
				}
				svResources_1.push_back(sv);//把该台服务器放到所有已购买服务器的尾部
				svBuys.push_back(svId);//同步更新该编号数组。
				buy_number++;//本波请求中，需购买的服务器的数量 + 1
			}
		}else{//这是一条删除虚拟机的请求
			string vmId=req[1];
			DeployInfo vmDeInfo;
			if(vmOnServer_1.count(vmId) != 0){//是当日部署，当日删除。不排除有这种情况的可能
				vmDeInfo = vmOnServer_1[vmId];
			}else{//是之前部署的
				vmDeInfo = vmOnServer[vmId];
			}
			int svId=vmDeInfo[0], occupiedCpu=vmDeInfo[1], occupiedMem=vmDeInfo[2];//获取部署信息
			Server &sv=svResources_1[svId];//这里使用 &, 因为要去修改服务器的资源量
			if(vmDeInfo.size() == 3){//该虚拟机之前是双节点部署的
				sv.cpuA += occupiedCpu;
				sv.cpuB += occupiedCpu;
				sv.memA += occupiedMem;
				sv.memB += occupiedMem;
			}else{//若长度为4表明该虚拟机之前是单节点部署的
				if(vmDeInfo[3] == 0){//之前是部署在A节点上
					sv.cpuA += occupiedCpu;
					sv.memA += occupiedMem;
				}else{
					sv.cpuB += occupiedCpu;
					sv.memB += occupiedMem;
				}
			}
			// vmOnServer_1 中保存该条信息，在之后的过程中再删除。难以理解，但是确实很重要
		}
	}
	return buy_number;//返回本波请求中，需购买服务器的数量
}

//处理每日请求
void handleOneDayRequests(int day){
	int purchTypeNumber=0, every_num=0;
	vector<string> day_purchase_info{""}; //记录每个类型购买了多少，字符串格式为 “（类型，数量）”, 先加入一个空字符串留给 purchTypeNumber
	distributeRequests();//处理前，将请求按服务器分波存放到svMapReq中
	//遍历svMapReq，处理每一波请求。每一波请求都是针对同一个类别的服务器（因为做了特殊的处理）
	for(auto key_value : svMapReq){
		string svType = key_value.first;//这波请求针对的服务器类型
		vector<Request> &reqs = key_value.second;//获取这波请求
		every_num = handleBranchRequests(svType, reqs);//处理每波请求
		//用某个线程的变量更新全局变量
		for(auto const &pair:vmOnServer_1){
			vmOnServer[pair.first] = pair.second;
		}
		//如果本次的服务器类型购买数量不是0
		if(every_num != 0){
			purchTypeNumber++;
			day_purchase_info.push_back("(" + svType + ", " + to_string(every_num) +")\n");
			vector<int> &svBuys=svMapBuy[svType];
			for(int i=0; i<every_num; i++){
				svBuys.push_back(svResources.size());//添加购买的服务器编号
				svResources.push_back(svInfos[svType]);//添加购买的服务器
				svRunVms.push_back(0);//为新购服务器添加“部署虚拟机个数”的记录
			}
			SERVERCOST += every_num * svInfos[svType].serverCost;
		}
	}
	
	//模拟请求，改资源，保存当天决策
	vector<string> day_deploy_info;
	DeployInfo depInfo;
	string vmId;
	int svId, occupiedCpu, occupiedMem;
	for(auto &req : reqInfos){
		if(req[0] == "add"){
			vmId = req[2];//虚拟机Id
			depInfo = vmOnServer[vmId];//虚拟机部署信息
			svId=depInfo[0], occupiedCpu=depInfo[1], occupiedMem=depInfo[2];
			Server &sv=svResources[svId];//找到对应的服务器，减少它的资源
			if(depInfo.size()==3){//双部署
				sv.cpuA -= occupiedCpu;
				sv.cpuB -= occupiedCpu;
				sv.memA -= occupiedMem;
				sv.memB -= occupiedMem;
				day_deploy_info.push_back("(" + to_string(depInfo[0]) + ")\n");
			}else{//单部署
				string nodeInfo = depInfo[3]==0 ? "A" : "B";//部署的结点信息
				if(nodeInfo == "A"){
					sv.cpuA -= occupiedCpu;
					sv.memA -= occupiedMem;
				}else{
					sv.cpuB -= occupiedCpu;
					sv.memB -= occupiedMem;
				}
				day_deploy_info.push_back("(" + to_string(depInfo[0]) + ", " + nodeInfo + ")\n");
			}
			svRunVms[svId]++;//对应服务器上运行的虚拟机个数 + 1
		}else{//删除
			vmId = req[1];//虚拟机Id
			depInfo = vmOnServer[vmId];//虚拟机部署信息
			svId=depInfo[0], occupiedCpu=depInfo[1], occupiedMem=depInfo[2];
			Server &sv=svResources[svId];//找到对应的服务器，增加它的资源
			if(depInfo.size()==3){//双部署
				sv.cpuA += occupiedCpu;
				sv.cpuB += occupiedCpu;
				sv.memA += occupiedMem;
				sv.memB += occupiedMem;
			}else{//单部署
				string nodeInfo = depInfo[3]==0 ? "A" : "B";//部署的结点信息
				if(nodeInfo == "A"){
					sv.cpuA += occupiedCpu;
					sv.memA += occupiedMem;
				}else{
					sv.cpuB += occupiedCpu;
					sv.memB += occupiedMem;
				}
			}
			vmOnServer.erase(vmId);//真正的删除部署信息
			svRunVms[svId]--;//对应服务器上运行的虚拟机个数 - 1
		}
	}
	
	day_purchase_info[0] = "(purchase, " + to_string(purchTypeNumber) + ")\n";//将purchTypeNumber转化成字符串放到 day_purchase_info 的首位
	purchase_info.push_back(day_purchase_info);//存一下每日的购买请求
	migrate_info.push_back(vector<string>{"(migration, 0)\n"});//存一下每日的迁移请求
	deploy_info.push_back(day_deploy_info);//存一下每日的部署请求
}

//开始处理请求
void handleRequests(){
	int reqDays=0, dayReqNumber=0;
	string op, reqVmType, reqVmId;
	scanf("%d", &reqDays);
	for (int day=0; day<reqDays; day++){
		scanf("%d", &dayReqNumber);
		reqInfos.clear();                               //清理前一天的请求
		for (int i=0; i<dayReqNumber; i++){
			cin>>op;                                    //读取请求类型
			if(op[1] == 'a'){
				cin>>reqVmType>>reqVmId;                //读需部署虚拟机的 类型 和 Id
				readRequest(op, reqVmType, reqVmId);    //解用户的添加请求，将请求信息加入到reqInfos中
			}else{
				cin>>reqVmId;                           //读需删除虚拟机的 Id
				readRequest(op, reqVmId);               //解用户的删除请求，将请求信息加入到reqInfos中
			}
		}
		handleOneDayRequests(day);                    //处理给定天的请求
		//computePowerCost();                            //计算每日成本
	}
}

//打印输出结果
void print(){
	for(int i=0; i<purchase_info.size(); i++){//遍历每天
		for(string &info:purchase_info[i]){//每天购买
			cout<<info;
		}
		for(string &info:migrate_info[i]){//每天迁移
			cout<<info;
		}
		for(string &info:deploy_info[i]){//每天部署
			cout<<info;
		}
	}
}

//无聊的测试
void test(){
	
}

int main(){
	//重定向标准输入和标准输出，题目要求从标准输入输出读取数据。提交时请注释
//	freopen(INPUT_REDIRECTION, "r", stdin);
//	freopen(OUTPUT_REDIRECTION, "w", stdout);
//	clock_t start, finish;
//  	start = clock();
	
	readServerAndVmInfos();//读取服务器和虚拟机信息
	createVmMapToSV();//创建每台虚拟机到服务器的映射关系
	handleRequests();//处理请求
	print();//打印输出结果
	
//	test();
	
//	finish = clock();
//	TOTALCOST = SERVERCOST + POWERCOST;//总成本
//	printf("\nCompute Time: %f s \n", double(finish-start)/CLOCKS_PER_SEC);
//	printf("\nServer Cost: %lld \nPower Cost: %lld \nTotal Cost: %lld \n", SERVERCOST, POWERCOST, TOTALCOST);
	return 0;
}